home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / gnu / gnpltsrc.lha / util.c < prev    next >
C/C++ Source or Header  |  1996-01-22  |  24KB  |  1,101 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: util.c,v 1.33 1995/12/07 21:41:12 drd Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - util.c */
  6. /*
  7.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Original Software:
  25.  *     Thomas Williams,  Colin Kelley.
  26.  * 
  27.  *   Gnuplot 2.0 additions:
  28.  *       Russell Lang, Dave Kotz, John Campbell.
  29.  *
  30.  *   Gnuplot 3.0 additions:
  31.  *       Gershon Elber and many others.
  32.  * 
  33.  */
  34.  
  35. #include <ctype.h>
  36. #include <math.h> /* get prototype for sqrt */
  37. #include "plot.h"
  38. #include "setshow.h" /* for month names etc */
  39.  
  40.  
  41. TBOOLEAN screen_ok;
  42.     /* TRUE if command just typed; becomes FALSE whenever we
  43.         send some other output to screen.  If FALSE, the command line
  44.         will be echoed to the screen before the ^ error message. */
  45.  
  46.  
  47. static char *num_to_str __P((double r));
  48. static void parse_esc __P((char *instr));
  49. static char * read_int __P((char *s, int nr, int *d));
  50.  
  51. /*
  52.  * chr_in_str() compares the characters in the string of token number t_num
  53.  * with c, and returns TRUE if a match was found.
  54.  */
  55. #ifdef ANSI_C
  56. int chr_in_str(int t_num, char c)
  57. #else
  58. int chr_in_str(t_num, c)
  59. int t_num;
  60. char c;
  61. #endif
  62. {
  63. register int i;
  64.  
  65.     if (!token[t_num].is_token)
  66.         return(FALSE);                /* must be a value--can't be equal */
  67.     for (i = 0; i < token[t_num].length; i++) {
  68.         if (input_line[token[t_num].start_index+i] == c)
  69.             return(TRUE);
  70.         }
  71.     return FALSE;
  72. }
  73.  
  74.  
  75. /*
  76.  * equals() compares string value of token number t_num with str[], and
  77.  *   returns TRUE if they are identical.
  78.  */
  79. int equals(t_num, str)
  80. int t_num;
  81. char *str;
  82. {
  83. register int i;
  84.  
  85.     if (!token[t_num].is_token)
  86.         return(FALSE);                /* must be a value--can't be equal */
  87.     for (i = 0; i < token[t_num].length; i++) {
  88.         if (input_line[token[t_num].start_index+i] != str[i])
  89.             return(FALSE);
  90.         }
  91.     /* now return TRUE if at end of str[], FALSE if not */
  92.     return(str[i] == '\0');
  93. }
  94.  
  95.  
  96.  
  97. /*
  98.  * almost_equals() compares string value of token number t_num with str[], and
  99.  *   returns TRUE if they are identical up to the first $ in str[].
  100.  */
  101. int almost_equals(t_num, str)
  102. int t_num;
  103. char *str;
  104. {
  105. register int i;
  106. register int after = 0;
  107. register start = token[t_num].start_index;
  108. register length = token[t_num].length;
  109.  
  110.     if (!token[t_num].is_token)
  111.         return(FALSE);                /* must be a value--can't be equal */
  112.     for (i = 0; i < length + after; i++) {
  113.         if (str[i] != input_line[start + i]) {
  114.             if (str[i] != '$')
  115.                 return(FALSE);
  116.             else {
  117.                 after = 1;
  118.                 start--;    /* back up token ptr */
  119.                 }
  120.             }
  121.         }
  122.  
  123.     /* i now beyond end of token string */
  124.  
  125.     return(after || str[i] == '$' || str[i] == '\0');
  126. }
  127.  
  128.  
  129.  
  130. int isstring(t_num)
  131. int t_num;
  132. {
  133.     
  134.     return(token[t_num].is_token &&
  135.            (input_line[token[t_num].start_index] == '\'' ||
  136.            input_line[token[t_num].start_index] == '\"'));
  137. }
  138.  
  139.  
  140. int isanumber(t_num)
  141. int t_num;
  142. {
  143.     return(!token[t_num].is_token);
  144. }
  145.  
  146.  
  147. int isletter(t_num)
  148. int t_num;
  149. {
  150.     return(token[t_num].is_token &&
  151.             ((isalpha(input_line[token[t_num].start_index]))||
  152.              (input_line[token[t_num].start_index] == '_')));
  153. }
  154.  
  155.  
  156. /*
  157.  * is_definition() returns TRUE if the next tokens are of the form
  158.  *   identifier =
  159.  *        -or-
  160.  *   identifier ( identifer {,identifier} ) =
  161.  */
  162. int is_definition(t_num)
  163. int t_num;
  164. {
  165.     /* variable? */
  166.     if(isletter(t_num) && equals(t_num+1,"="))
  167.         return 1;
  168.  
  169.     /* function? */
  170.     /* look for dummy variables */
  171.     if(isletter(t_num) && equals(t_num+1,"(") && isletter(t_num+2)) {
  172.         t_num += 3;  /* point past first dummy */
  173.         while(equals(t_num,",")) {
  174.             if(!isletter(++t_num))
  175.                 return 0;
  176.             t_num += 1;
  177.         }
  178.         return(equals(t_num,")") && equals(t_num+1,"="));
  179.     }
  180.  
  181.     /* neither */
  182.     return 0;
  183. }
  184.  
  185.  
  186.  
  187. /*
  188.  * copy_str() copies the string in token number t_num into str, appending
  189.  *   a null.  No more than max chars are copied (including \0).
  190.  */
  191. void copy_str(str, t_num, max)
  192. char str[];
  193. int t_num;
  194. int max;
  195. {
  196. register int i = 0;
  197. register int start = token[t_num].start_index;
  198. register int count;
  199.  
  200.     if ((count = token[t_num].length) >= max) {
  201.         count = max-1;
  202. #ifdef DEBUG_STR
  203.         fprintf(stderr, "str buffer overflow in copy_str");
  204. #endif
  205.     }
  206.     do {
  207.         str[i++] = input_line[start++];
  208.         } while (i != count);
  209.     str[i] = '\0';
  210. }
  211.  
  212. /* length of token string */
  213. int token_len(t_num)
  214. int t_num;
  215. {
  216.     return (token[t_num].length);
  217. }
  218.  
  219. /*
  220.  * quote_str() does the same thing as copy_str, except it ignores the
  221.  *   quotes at both ends.  This seems redundant, but is done for
  222.  *   efficency.
  223.  */
  224. void quote_str(str, t_num, max)
  225. char str[];
  226. int t_num;
  227. int max;
  228. {
  229. register int i = 0;
  230. register int start = token[t_num].start_index + 1;
  231. register int count;
  232.  
  233.     if ((count = token[t_num].length - 2) >= max) {
  234.         count = max-1;
  235. #ifdef DEBUG_STR
  236.         fprintf(stderr, "str buffer overflow in quote_str");
  237. #endif
  238.     }
  239.     if (count>0) {
  240.         do {
  241.             str[i++] = input_line[start++];
  242.             } while (i != count);
  243.     }
  244.     str[i] = '\0';
  245.     /* convert \t and \nnn (octal) to char if in double quotes */
  246.     if ( input_line[token[t_num].start_index] == '"' )
  247.         parse_esc(str);
  248. }
  249.  
  250.  
  251. /*
  252.  *    capture() copies into str[] the part of input_line[] which lies between
  253.  *    the begining of token[start] and end of token[end].
  254.  */
  255. void capture(str,start,end,max)
  256. char str[];
  257. int start,end;
  258. int max;
  259. {
  260. register int i,e;
  261.  
  262.     e = token[end].start_index + token[end].length;
  263.     if(e-token[start].start_index>=max) {
  264.         e=token[start].start_index+max-1;
  265. #ifdef DEBUG_STR
  266.         fprintf(stderr, "str buffer overflow in capture");
  267. #endif
  268.     }
  269.  
  270.     for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  271.         *str++ = input_line[i];
  272.     *str = '\0';
  273. }
  274.  
  275.  
  276. /*
  277.  *    m_capture() is similar to capture(), but it mallocs storage for the
  278.  *  string.
  279.  */
  280. void m_capture(str,start,end)
  281. char **str;
  282. int start,end;
  283. {
  284. register int i,e;
  285. register char *s;
  286.  
  287.     if (*str)        /* previous pointer to malloc'd memory there */
  288.         free(*str);
  289.     e = token[end].start_index + token[end].length;
  290.     *str = alloc((unsigned long)(e - token[start].start_index + 1), "string");
  291.      s = *str;
  292.      for (i = token[start].start_index; i < e && input_line[i] != '\0'; i++)
  293.       *s++ = input_line[i];
  294.      *s = '\0';
  295. }
  296.  
  297.  
  298. /*
  299.  *    m_quote_capture() is similar to m_capture(), but it removes
  300.     quotes from either end if the string.
  301.  */
  302. void m_quote_capture(str,start,end)
  303. char **str;
  304. int start,end;
  305. {
  306. register int i,e;
  307. register char *s;
  308.  
  309.     if (*str)        /* previous pointer to malloc'd memory there */
  310.         free(*str);
  311.     e = token[end].start_index + token[end].length-1;
  312.     *str = alloc((unsigned long)(e - token[start].start_index + 1), "string");
  313.      s = *str;
  314.     for (i = token[start].start_index + 1; i < e && input_line[i] != '\0'; i++)
  315.      *s++ = input_line[i];
  316.     *s = '\0';
  317. }
  318.  
  319.  
  320. void convert(val_ptr, t_num)
  321. struct value *val_ptr;
  322. int t_num;
  323. {
  324.     *val_ptr = token[t_num].l_val;
  325. }
  326.  
  327. static char *num_to_str(r)
  328. double r;
  329. {
  330.     static i = 0;
  331.     static char s[4][25];
  332.     int j = i++;
  333.  
  334.     if ( i > 3 ) i = 0;
  335.  
  336.     sprintf( s[j], "%.15g", r );
  337.     if ( strchr( s[j], '.' ) == NULL &&
  338.          strchr( s[j], 'e' ) == NULL &&
  339.          strchr( s[j], 'E' ) == NULL )
  340.         strcat( s[j], ".0" );
  341.  
  342.     return s[j];
  343.  
  344. void disp_value(fp,val)
  345. FILE *fp;
  346. struct value *val;
  347. {
  348.     switch(val->type) {
  349.         case INTGR:
  350.             fprintf(fp,"%d",val->v.int_val);
  351.             break;
  352.         case CMPLX:
  353.             if (val->v.cmplx_val.imag != 0.0 )
  354.                 fprintf(fp,"{%s, %s}",
  355.                     num_to_str(val->v.cmplx_val.real),
  356.                     num_to_str(val->v.cmplx_val.imag));
  357.             else
  358.                 fprintf(fp,"%s",
  359.                     num_to_str(val->v.cmplx_val.real));
  360.             break;
  361.         default:
  362.             int_error("unknown type in disp_value()",NO_CARET);
  363.     }
  364. }
  365.  
  366.  
  367. double
  368. real(val)        /* returns the real part of val */
  369. struct value *val;
  370. {
  371.     switch(val->type) {
  372.         case INTGR:
  373.             return((double) val->v.int_val);
  374.         case CMPLX:
  375.             return(val->v.cmplx_val.real);
  376.     }
  377.     int_error("unknown type in real()",NO_CARET);
  378.     /* NOTREACHED */
  379.     return((double)0.0);
  380. }
  381.  
  382.  
  383. double
  384. imag(val)        /* returns the imag part of val */
  385. struct value *val;
  386. {
  387.     switch(val->type) {
  388.         case INTGR:
  389.             return(0.0);
  390.         case CMPLX:
  391.             return(val->v.cmplx_val.imag);
  392.     }
  393.     int_error("unknown type in imag()",NO_CARET);
  394.     /* NOTREACHED */
  395.     return((double)0.0);
  396. }
  397.  
  398.  
  399.  
  400. double
  401. magnitude(val)        /* returns the magnitude of val */
  402. struct value *val;
  403. {
  404.     switch(val->type) {
  405.         case INTGR:
  406.             return((double) abs(val->v.int_val));
  407.         case CMPLX:
  408.             return(sqrt(val->v.cmplx_val.real*
  409.                     val->v.cmplx_val.real +
  410.                     val->v.cmplx_val.imag*
  411.                     val->v.cmplx_val.imag));
  412.     }
  413.     int_error("unknown type in magnitude()",NO_CARET);
  414.     /* NOTREACHED */
  415.     return((double)0.0);
  416. }
  417.  
  418.  
  419.  
  420. double
  421. angle(val)        /* returns the angle of val */
  422. struct value *val;
  423. {
  424.     switch(val->type) {
  425.         case INTGR:
  426.             return((val->v.int_val >= 0) ? 0.0 : Pi);
  427.         case CMPLX:
  428.             if (val->v.cmplx_val.imag == 0.0) {
  429.                 if (val->v.cmplx_val.real >= 0.0)
  430.                     return(0.0);
  431.                 else
  432.                     return(Pi);
  433.             }
  434.             return(atan2(val->v.cmplx_val.imag,
  435.                      val->v.cmplx_val.real));
  436.     }
  437.     int_error("unknown type in angle()",NO_CARET);
  438.     /* NOTREACHED */
  439.     return((double)0.0);
  440. }
  441.  
  442.  
  443. struct value *
  444. Gcomplex(a,realpart,imagpart)
  445. struct value *a;
  446. double realpart, imagpart;
  447. {
  448.     a->type = CMPLX;
  449.     a->v.cmplx_val.real = realpart;
  450.     a->v.cmplx_val.imag = imagpart;
  451.     return(a);
  452. }
  453.  
  454.  
  455. struct value *
  456. Ginteger(a,i)
  457. struct value *a;
  458. int i;
  459. {
  460.     a->type = INTGR;
  461.     a->v.int_val = i;
  462.     return(a);
  463. }
  464.  
  465.  
  466. #if !defined(vms) && !defined(HAVE_STRERROR)
  467. /* substitute for systems that don't have ANSI function strerror */
  468.  
  469. extern int sys_nerr;
  470. extern char *sys_errlist[];
  471.  
  472. char *strerror(no)
  473. int no;
  474. {
  475.   static char res_str[30];
  476.  
  477.   if(no>sys_nerr) {
  478.     sprintf(res_str, "unknown errno %d", no);
  479.     return res_str;
  480.   } else {
  481.     return sys_errlist[no];
  482.   }
  483. }
  484. #endif
  485.  
  486.  
  487. void os_error(str,t_num)
  488. char str[];
  489. int t_num;
  490. {
  491. #ifdef vms
  492. static status[2] = {1, 0};        /* 1 is count of error msgs */
  493. #endif
  494.  
  495. register int i;
  496.  
  497.     /* reprint line if screen has been written to */
  498.  
  499.     if (t_num != NO_CARET) {        /* put caret under error */
  500.         if (!screen_ok)
  501.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  502.  
  503.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  504.             (void) putc(' ',stderr);
  505.         for (i = 0; i < token[t_num].start_index; i++) {
  506.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  507.             }
  508.         (void) putc('^',stderr);
  509.         (void) putc('\n',stderr);
  510.     }
  511.  
  512.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  513.         (void) putc(' ',stderr);
  514.     fprintf(stderr,"%s\n",str);
  515.  
  516.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  517.         (void) putc(' ',stderr);
  518.      if (!interactive)
  519.       if (infile_name != NULL)
  520.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  521.       else
  522.         fprintf(stderr,"line %d: ", inline_num);
  523.  
  524.  
  525. #ifdef vms
  526.     status[1] = vaxc$errno;
  527.     sys$putmsg(status);
  528.     (void) putc('\n',stderr);
  529. #else /* vms */
  530.     fprintf(stderr,"(%s)\n\n", strerror(errno));
  531. #endif /* vms */
  532.  
  533.     longjmp(env, TRUE);    /* bail out to command line */
  534. }
  535.  
  536.  
  537. void int_error(str,t_num)
  538. char str[];
  539. int t_num;
  540. {
  541. register int i;
  542.  
  543.     /* reprint line if screen has been written to */
  544.  
  545.     if (t_num != NO_CARET) {        /* put caret under error */
  546.         if (!screen_ok)
  547.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  548.  
  549.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  550.             (void) putc(' ',stderr);
  551.         for (i = 0; i < token[t_num].start_index; i++) {
  552.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  553.             }
  554.         (void) putc('^',stderr);
  555.         (void) putc('\n',stderr);
  556.     }
  557.  
  558.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  559.         (void) putc(' ',stderr);
  560.      if (!interactive)
  561.       if (infile_name != NULL)
  562.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  563.       else
  564.         fprintf(stderr,"line %d: ", inline_num);
  565.      fprintf(stderr,"%s\n\n", str);
  566.  
  567.     longjmp(env, TRUE);    /* bail out to command line */
  568. }
  569.  
  570. void int_warn(str,t_num)
  571. char str[];
  572. int t_num;
  573. {
  574. register int i;
  575.  
  576. /* Warn without bailing out to command line. Not a user error */
  577.  
  578.     /* reprint line if screen has been written to */
  579.  
  580.     if (t_num != NO_CARET) {        /* put caret under error */
  581.         if (!screen_ok)
  582.             fprintf(stderr,"\n%s%s\n", PROMPT, input_line);
  583.  
  584.         for (i = 0; i < sizeof(PROMPT) - 1; i++)
  585.             (void) putc(' ',stderr);
  586.         for (i = 0; i < token[t_num].start_index; i++) {
  587.             (void) putc((input_line[i] == '\t') ? '\t' : ' ',stderr);
  588.             }
  589.         (void) putc('^',stderr);
  590.         (void) putc('\n',stderr);
  591.     }
  592.  
  593.     for (i = 0; i < sizeof(PROMPT) - 1; i++)
  594.         (void) putc(' ',stderr);
  595.      if (!interactive)
  596.       if (infile_name != NULL)
  597.         fprintf(stderr,"\"%s\", line %d: ", infile_name, inline_num);
  598.       else
  599.         fprintf(stderr,"line %d: ", inline_num);
  600.      fprintf(stderr,"warning: %s\n", str);
  601.  
  602. } /* int_warn */
  603.  
  604. /* Lower-case the given string (DFK) */
  605. /* Done in place. */
  606. void
  607. lower_case(s)
  608.      char *s;
  609. {
  610.   register char *p = s;
  611.  
  612.   while (*p != '\0') {
  613.     if (isupper(*p))
  614.      *p = tolower(*p);
  615.     p++;
  616.   }
  617. }
  618.  
  619. /* Squash spaces in the given string (DFK) */
  620. /* That is, reduce all multiple white-space chars to single spaces */
  621. /* Done in place. */
  622. void
  623. squash_spaces(s)
  624.      char *s;
  625. {
  626.   register char *r = s;        /* reading point */
  627.   register char *w = s;        /* writing point */
  628.   TBOOLEAN space = FALSE;        /* TRUE if we've already copied a space */
  629.  
  630.   for (w = r = s; *r != '\0'; r++) {
  631.      if (isspace(*r)) {
  632.         /* white space; only copy if we haven't just copied a space */
  633.         if (!space) {
  634.             space = TRUE;
  635.             *w++ = ' ';
  636.         }                /* else ignore multiple spaces */
  637.      } else {
  638.         /* non-space character; copy it and clear flag */
  639.         *w++ = *r;
  640.         space = FALSE;
  641.      }
  642.   }
  643.   *w = '\0';                /* null terminate string */
  644. }
  645.  
  646. static int mndday[12] = { 31,28,31,30,31,30,31,31,30,31,30,31};
  647.  
  648. /* days in year */
  649. int
  650. gdysize(yr)
  651. int yr;
  652. {
  653.  
  654.     if (!(yr%4)) {
  655.         if ((!(yr%100)) && yr%400) 
  656.             return(365);
  657.         return(366);
  658.     }
  659.     return(365);
  660. }
  661.  
  662.  
  663. /* new strptime() and gmtime() to allow time to be read as 24 hour,
  664.  * and spaces in the format string. time is converted to seconds from
  665.  * year 2000.... */  
  666.  
  667. char *
  668. gstrptime(s,fmt,tm)
  669. char *s;
  670. char *fmt;
  671. struct tm *tm;
  672. {
  673.     int yday, date;
  674.  
  675.     date = yday = 0;
  676.     tm->tm_mday = 0;
  677.     tm->tm_mon = tm->tm_year = tm->tm_yday = tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
  678.  
  679.     while ( *fmt != '\0' ) {
  680.         while(*s == *fmt) {s++; fmt++;}
  681.         if ( *fmt != '%' ) 
  682.             break;
  683.         fmt++;
  684.         if ( *fmt == 'd' ) { /* read a day of month */
  685.             s = read_int(s,2,&tm->tm_mday);
  686.             date++;
  687.         } else if ( *fmt == 'm' ) {
  688.             s = read_int(s,2,&tm->tm_mon);
  689.             date++;
  690.             tm->tm_mon--;
  691.         } else if ( *fmt == 'y' ) {
  692.             s = read_int(s,2,&tm->tm_year);
  693.             date++;
  694.             tm->tm_year += 1900;
  695.         } else if ( *fmt == 'Y' ) {
  696.             s = read_int(s,4,&tm->tm_year);
  697.             date++;
  698.             /* tm->tm_year -= 1900; */
  699.             /* HOE tm->tm_year %= 100; */
  700.         } else if ( *fmt == 'j' ) {
  701.             s = read_int(s,3,&tm->tm_yday);
  702.             tm->tm_yday--;
  703.             date++;
  704.             yday++;
  705.         } else if ( *fmt == 'H' ) {
  706.             s = read_int(s,2,&tm->tm_hour);
  707.         } else if ( *fmt == 'M' ) {
  708.             s = read_int(s,2,&tm->tm_min);
  709.         } else if ( *fmt == 'S' ) {
  710.             s = read_int(s,2,&tm->tm_sec);
  711.         }
  712.         fmt++;
  713.     }
  714.     /* if (!yday && date) { */
  715.     if (date) {
  716.         /* 
  717.         tm->tm_yday = 0;
  718.         for(i=0;i<tm->tm_mon;i++) {
  719.             tm->tm_yday += mndday[i] + (i==1 && (gdysize(tm->tm_year)>365));
  720.         }
  721.         tm->tm_yday += tm->tm_mday-1;
  722.         */
  723.         if (yday) {
  724.             if ( tm->tm_yday < 0 || tm->tm_yday > gdysize(tm->tm_year)) {
  725.                 int_error("illegal day of year",NO_CARET);
  726.                 return(NULL);
  727.             }
  728.         } else {
  729.             if ( tm->tm_mon < 0 || tm->tm_mon > 11 ) {
  730.                 int_error("illegal month",NO_CARET);
  731.                 return(NULL);
  732.             }
  733.             if ( tm->tm_mday < 1 || tm->tm_mday > mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year)>365)) ) {
  734.                 int_error("illegal day of month",NO_CARET);
  735.                 return(NULL);
  736.             }
  737.         }
  738.     }
  739.     if ( tm->tm_hour < 0 || tm->tm_hour > 24 ) {
  740.         int_error("illegal hour",NO_CARET);
  741.         return(NULL);
  742.     }
  743.     if ( tm->tm_min < 0 || tm->tm_min > 60 ) {
  744.         int_error("illegal minute",NO_CARET);
  745.         return(NULL);
  746.     }
  747.     if ( tm->tm_sec < 0 || tm->tm_sec > 60 ) {
  748.         int_error("illegal second",NO_CARET);
  749.         return(NULL);
  750.     }
  751.     return(s);
  752. }
  753.  
  754. static char *
  755. read_int(s,nr,d)
  756. char *s;
  757. int nr, *d;
  758. {
  759.     char num[8];
  760.     int i;
  761.  
  762.     i = 0;
  763.     while(i<nr) {
  764.         if( *s >= '0' && *s <= '9' ) {
  765.             num[i++] = *s++;
  766.         } else {
  767.             break;
  768.         }
  769.     }
  770.     num[i] = '\0';
  771.     sscanf(num,"%d",d);
  772.     return(s);
  773. }
  774.  
  775.  
  776. int 
  777. gstrftime(s,bsz,fmt,clock)
  778. char *s;
  779. int bsz;
  780. char *fmt;
  781. double clock;
  782. {
  783.     int xstrftime();
  784.     int days;
  785.     time_t cl;
  786.     struct tm tm;
  787.     struct tm *xtm;
  788.  
  789.     ggmtime(&tm,clock);
  790.     /* weekday, 0 = sunday */
  791.     cl = 0;
  792.     xtm = gmtime(&cl);
  793.     /* antall dager */
  794.     days = (int) (clock+SEC_OFFS_SYS)/DAY_SEC;
  795.     /* weekrest */
  796.     days %= 7;
  797.     if ( days < 0 ) days += 7;
  798.     tm.tm_wday = (xtm->tm_wday+days)%7;
  799. #if 0
  800.     if ((tm.tm_zone = (char *) malloc(strlen(xtm->tm_zone)+1))) 
  801.         strcpy(tm.tm_zone,xtm->tm_zone);
  802.     /* printf("zone: %s - %s\n",tm.tm_zone,xtm->tm_zone); */
  803. #endif
  804.  
  805.     return(xstrftime(s,bsz,fmt,&tm));
  806. }
  807.  
  808. int 
  809. xstrftime(str,bsz,fmt,tm)
  810. char *str;
  811. int bsz;
  812. char *fmt;
  813. struct tm *tm;
  814. {
  815.     int l;
  816.     char *p, *s;
  817.  
  818.     p = fmt;
  819.     s = str;
  820.     memset(s,'\0',bsz+1);
  821.     l=0;
  822.     while (*p != '\0') {
  823.         if (*p != '%') {
  824.             if ( l >= bsz ) return(0);
  825.             *s++ = *p++;
  826.             l++;
  827.         } else {
  828.             p++;
  829.             if ( *p == '%' ) {
  830.                 if ( l >= bsz ) return(0);
  831.                 *s = '%';
  832.             } else if ( *p == 'a' ) {    
  833.                 if ((l+strlen(abbrev_day_names[tm->tm_wday])) > bsz ) return(0);
  834.                 sprintf(s,"%s",abbrev_day_names[tm->tm_wday]);
  835.             } else if ( *p == 'A' ) {    
  836.                 if(l+strlen(full_day_names[tm->tm_wday]) > bsz) return(0);
  837.                 sprintf(s,"%s",full_day_names[tm->tm_wday]);
  838.             } else if ( *p == 'b' || *p == 'h' ) {
  839.                 if(l+strlen(abbrev_month_names[tm->tm_mon])> bsz) return(0);
  840.                 sprintf(s,"%s",abbrev_month_names[tm->tm_mon]);
  841.             } else if ( *p == 'B' ) {
  842.                 if(l+strlen(full_month_names[tm->tm_mon]) > bsz) return(0);
  843.                 sprintf(s,"%s",full_month_names[tm->tm_mon]);
  844.             } else if ( *p == 'c' ) {
  845.                 if (!xstrftime(s,bsz-l,"%x %X",tm)) {
  846.                     return(0);
  847.                 }
  848. #if 0
  849.             } else if ( *p == 'C' ) {
  850.                 if (!xstrftime(s,bsz-l,dtc->ldate_format,tm)) {
  851.                     return(0);
  852.                 }
  853. #endif
  854.             } else if ( *p == 'd' ) {
  855.                 if ( bsz - l < 2 ) return(0);
  856.                 sprintf(s,"%02d",tm->tm_mday);
  857.             } else if ( *p == 'D' ) {
  858.                 if (!xstrftime(s,bsz-l,"%m/%d/%y",tm)) {
  859.                     return(0);
  860.                 }
  861.             } else if ( *p == 'e' ) {
  862.                 if ( bsz - l < 2 ) return(0);
  863.                 sprintf(s,"%2d",tm->tm_mday);
  864.             } else if ( *p == 'H' ) {
  865.                 if ( bsz - l < 2 ) return(0);
  866.                 sprintf(s,"%02d",tm->tm_hour);
  867.             } else if ( *p == 'I' ) {
  868.                 if ( bsz - l < 2 ) return(0);
  869.                 sprintf(s,"%02d",tm->tm_hour%12);
  870.             } else if ( *p == 'j' ) {
  871.                 if ( bsz - l < 3 ) return(0);
  872.                 sprintf(s,"%03d",tm->tm_yday+1);
  873.             } else if ( *p == 'k' ) {
  874.                 if ( bsz - l < 2 ) return(0);
  875.                 sprintf(s,"%2d",tm->tm_hour);
  876.             } else if ( *p == 'l' ) {
  877.                 if ( bsz - l < 2 ) return(0);
  878.                 sprintf(s,"%2d",tm->tm_hour%12);
  879.             } else if ( *p == 'm' ) {
  880.                 if ( bsz - l < 2 ) return(0);
  881.                 sprintf(s,"%02d",tm->tm_mon+1);
  882.             } else if ( *p == 'M' ) {
  883.                 if ( bsz - l < 2 ) return(0);
  884.                 sprintf(s,"%02d",tm->tm_min);
  885.             } else if ( *p == 'n' ) {
  886.                 if ( bsz >= l ) return(0);
  887.                 *s = '\n';
  888.             } else if ( *p == 'p' ) {
  889.                 if(l+strlen((tm->tm_hour<12)?"am":"pm") > bsz) return(0);
  890.                 sprintf(s,"%s",(tm->tm_hour<12)?"am":"pm");
  891.             } else if ( *p == 'r' ) {
  892.                 if (!xstrftime(s,bsz-l,"%I:%M:%S %p",tm)) {
  893.                     return(0);
  894.                 }
  895.             } else if ( *p == 'R' ) {
  896.                 if (!xstrftime(s,bsz-l,"%H:%M",tm)) {
  897.                     return(0);
  898.                 }
  899.             } else if ( *p == 'S' ) {
  900.                 if ( bsz - l < 2 ) return(0);
  901.                 sprintf(s,"%02d",tm->tm_sec);
  902.             } else if ( *p == 't' ) {
  903.                 if ( bsz >= l ) return(0);
  904.                 *s = '\t';
  905.             } else if ( *p == 'T' ) {
  906.                 if (!xstrftime(s,bsz-l,"%H:%M:%S",tm)) {
  907.                     return(0);
  908.                 }
  909.             } else if ( *p == 'W' ) { /* mon 1 day of week */
  910.                 int week, bw;
  911.  
  912.                 if ( bsz - l < 2 ) return(0);
  913.                 if ( tm->tm_yday <= tm->tm_wday ) {
  914.                     week = 1;
  915.                     if ( (tm->tm_mday - tm->tm_yday) > 4 ) {
  916.                         week = 52;
  917.                     } 
  918.                     if ( tm->tm_yday == tm->tm_wday && tm->tm_wday == 0 ) week = 52;
  919.                 } else {
  920.                     bw = tm->tm_yday - tm->tm_wday; /* sun prev week */
  921.                     if ( tm->tm_wday > 0 ) bw += 7; /* sun end of week */
  922.                     week = (int) bw/7;
  923.                     if ( (bw%7) > 2 ) { /* jan 1 is before friday */
  924.                         week++;
  925.                     }
  926.                 }
  927.                 sprintf(s,"%02d",week);
  928.             } else if ( *p == 'U' ) { /* sun 1 day of week */
  929.                 int week, bw;
  930.  
  931.                 if ( bsz - l < 2 ) return(0);
  932.                 if ( tm->tm_yday <= tm->tm_wday ) {
  933.                     week = 1;
  934.                     if ( (tm->tm_mday - tm->tm_yday) > 4 ) {
  935.                         week = 52;
  936.                     } 
  937.                 } else {
  938.                     bw = tm->tm_yday - tm->tm_wday-1; /* sat prev week */
  939.                     if ( tm->tm_wday >= 0 ) bw += 7; /* sat end of week */
  940.                     week = (int) bw/7;
  941.                     if ( (bw%7) > 1 ) { /* jan 1 is before friday */
  942.                         week++;
  943.                     }
  944.                 }
  945.                 sprintf(s,"%02d",week);
  946.             } else if ( *p == 'w' ) { /* day of week, sun=0 */
  947.                 if ( bsz - l < 2 ) return(0);
  948.                 sprintf(s,"%02d",tm->tm_wday);
  949. #if 0
  950.             } else if ( *p == 'x' ) { /* locales date format */
  951.                 if (!xstrftime(s,bsz-l,dtc->sdate_format,tm)) {
  952.                     return(0);
  953.                 }
  954.             } else if ( *p == 'X' ) { /* locales time format */
  955.                 if (!xstrftime(s,bsz-l,dtc->time_format,tm)) {
  956.                     return(0);
  957.                 }
  958. #endif
  959.             } else if ( *p == 'y' ) {
  960.                 if ( bsz - l < 2 ) return(0);
  961.                 sprintf(s,"%02d",tm->tm_year%100);
  962.             } else if ( *p == 'Y' ) {
  963.                 if ( bsz - l < 4 ) return(0);
  964.                 sprintf(s,"%04d",tm->tm_year);
  965. #if 0
  966.             } else if ( *p == 'Z' ) {
  967.                 if ( bsz - l < strlen(tm->tm_zone) ) return(0);
  968.                 sprintf(s,"%s",tm->tm_zone);
  969. #endif
  970.             }
  971.             p++;
  972.             while ( *s != '\0' ) {
  973.                 s++;
  974.                 l++;
  975.             }
  976.         }
  977.     }
  978.     return(l);
  979. }
  980.  
  981. /* time_t  */
  982. double
  983. gtimegm(tm)
  984. struct tm *tm;
  985. {
  986.     register int i;
  987.     /* returns sec from year ZERO_YEAR, defined in plot.h */
  988.     double dsec;
  989.  
  990.     dsec = 0;
  991.     if ( tm->tm_year < ZERO_YEAR ) {
  992.         for(i=tm->tm_year;i<ZERO_YEAR;i++) {
  993.             dsec -= (double) gdysize(i);
  994.         }
  995.     } else {
  996.         for(i=ZERO_YEAR;i<tm->tm_year;i++) {
  997.             dsec += (double) gdysize(i);
  998.         }
  999.     }
  1000.     if ( tm->tm_mday > 0 ) {
  1001.         for (i=0;i<tm->tm_mon;i++) {
  1002.             dsec += (double) mndday[i] + (i==1 && (gdysize(tm->tm_year)>365));
  1003.         }
  1004.         dsec += (double) tm->tm_mday-1;
  1005.     } else {
  1006.         dsec += (double) tm->tm_yday;
  1007.     }
  1008.     dsec *= (double) 24;
  1009.  
  1010.     dsec += tm->tm_hour;
  1011.     dsec *= 60.0;
  1012.     dsec += tm->tm_min;
  1013.     dsec *= 60.0;
  1014.     dsec += tm->tm_sec;
  1015.  
  1016.     return(dsec);
  1017. }
  1018.  
  1019. int
  1020. ggmtime(tm,clock)
  1021. struct tm *tm;
  1022. /* time_t clock; */
  1023. double clock;
  1024. {
  1025.     /* clock is relative to ZERO_YEAR, jan 1, 00:00:00,defined in plot.h */
  1026.     int i, days;
  1027.     
  1028.     tm->tm_year = ZERO_YEAR;
  1029.     tm->tm_mday = tm->tm_yday = tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0; 
  1030.     if ( clock < 0 ) {
  1031.         while ( clock < 0 ) {
  1032.             tm->tm_year --;
  1033.             clock += gdysize(tm->tm_year)*DAY_SEC; /* 24*3600 */
  1034.         }
  1035.     } else {
  1036.         while ( clock >= (gdysize(tm->tm_year)*DAY_SEC) ) {
  1037.             clock -= gdysize(tm->tm_year)*DAY_SEC;
  1038.             tm->tm_year ++;
  1039.         }
  1040.     }
  1041.     tm->tm_yday = (int)clock/DAY_SEC;
  1042.     clock -= tm->tm_yday*DAY_SEC;
  1043.     tm->tm_hour = (int)clock/3600;
  1044.     clock -= tm->tm_hour*3600;
  1045.     tm->tm_min = (int)clock/60;
  1046.     clock -= tm->tm_min*60;
  1047.     tm->tm_sec = (int)clock;
  1048.     days = tm->tm_yday;
  1049.     while ( days >= (i = mndday[tm->tm_mon] + (tm->tm_mon==1 && (gdysize(tm->tm_year)>365)))) {
  1050.         days -= i;
  1051.         tm->tm_mon ++;
  1052.     }
  1053.     tm->tm_mday = days+1;
  1054.  
  1055.     return(0);
  1056. }
  1057.  
  1058. static void
  1059. parse_esc(instr)
  1060. char *instr;
  1061. {
  1062.     char *s=instr, *t=instr;
  1063.  
  1064.     /* the string will always get shorter, so we can do the
  1065.      * conversion in situ
  1066.      */
  1067.  
  1068.     while (*s != '\0' ) {
  1069.         if ( *s == '\\' ) {
  1070.             s++;
  1071.             if ( *s == '\\' ) {
  1072.                 *t++ = '\\';
  1073.                 s++;
  1074.             } else if ( *s == 'n' ) {
  1075.                 *t++ = '\n';
  1076.                 s++;
  1077.             } else if ( *s == 'r' ) {
  1078.                 *t++ = '\r';
  1079.                 s++;
  1080.             } else if ( *s == 't' ) {
  1081.                 *t++ = '\t';
  1082.                 s++;
  1083.             } else if ( *s >= '0' && *s <= '7' ) {
  1084.                 int i,n;
  1085.                 if ( sscanf(s,"%o%n",&i, &n) > 0 ) {
  1086.                     *t++ = i;
  1087.                     s+=n;
  1088.                 } else {
  1089.                        /* int_error("illegal octal number ", c_token); */
  1090.                        *t++ = '\\';
  1091.                        *t++ = *s++;
  1092.                 }
  1093.             }
  1094.         } else {
  1095.             *t++ = *s++;
  1096.         }
  1097.     }
  1098.     *t = '\0';
  1099. }
  1100.